//! Trait 翻译成中文是特征，翻译过来反而不好理解，后面就直接用trait这个词，它表示一组抽象行为，也可以存在默认行为，和java的interface一样，
//! 下面会按照顺序trait声明，带关联类型的trait，泛型trait，trait限定，trait的继承，trait的默认实现，trait的泛型方法，trait的静态方法，trait的动态分发等来介绍。

use core::str;
use std::fmt::Display;




/// 声明一个trait, 没有任何行为，可以作为一个标记限定来用
#[allow(dead_code)]
trait Trait1 {

}

/// 声明一个trait,这个例子就是trait最简单用法
#[allow(dead_code)]
trait Trait2 {
    ///  声明一个实例方法
    fn foo(&self);
    ///  声明一个实例方法，返回一个i32
    fn foo2(&self) -> i32;
    ///  声明一个静态方法，接受一个i32参数，返回一个i32
    fn foo3(&self,i: i32) -> i32;
}

/// 这个trait定义是一个稍微复杂的例子， 带关联类型，泛型类型
/// :Display表示实现类必须实现Display trait
#[allow(dead_code)]
trait Trait3<T>: Display {
    /// 关联类型，具体类型由实现类决定
    type Item;
    ///  限定关联类型必须实现Display，具体类型由实现类决定
    type Item2: Display;
    ///  声明一个实例方法，接受一个泛型参数，返回一个i32
    fn foo4(&self, t: T) -> i32;

    ///  声明一个实例方法，接受一个泛型参数，返回一个关联类型
    ///  &self表示实现类必须实现Trait3 trait
    fn foo5<'a, B>(&self, t: B) -> Self::Item;
    
}

/// 这个不是trait的声明，是个使用的例子，用来表示trait的静态分发,编译器在编译时生成具体类型的方法代码,无运行时开销，但会增加二进制大小
/// T后面的trait限定不是必须的，同样是代表静态分发的trait，另外也有一个关键字impl，
/// 注意：trait是不能直接用在参数或者返回值上，因为rust在运行时需要知道参数或者返回值的具体类型大小，，比如下面这个函数，会在编译期间由具体的调用来当作上下文决定出T的具体类型是什么,
/// 但是泛型T是不能和参数一样直接用在返回值上，编译器推导不出来，除非参数也由同样的泛型参数定义 ,这个会导致编译异常fn fn2<T:Trait2>() -> T{} 
#[allow(dead_code)]
fn fn1<T:Trait2>(t: T)  {
    t.foo();
}

#[allow(dead_code)]
fn fn2<T:Trait2>(t: T) -> T {
    t
}

struct S1;

impl Trait1 for S1 {
    
}

#[allow(dead_code)]
fn fn3<T:Trait1>() -> impl  Trait1 {
    S1   
}

/// 动态分发是在运行时判断的具体类型，会带来微量的性能耗损。 动态分发有两种方式，由两个关键字可以确定，impl和dyn，impl通常用在静态分发，但是根据使用场景也可以动态分发，
/// dyn关键字表示动态分发，编译器在运行时根据具体的类型来决定调用哪个方法，
#[allow(dead_code)]
fn fn4(t: & dyn Trait2)  {
    t.foo();
}

#[allow(dead_code)]
fn fn5(t: &dyn Trait2) -> Box<dyn Trait1> {
    Box::new(S1)
}



#[cfg(test)]
mod test {
    // =======trait定义========
    trait MyTrait {
        /// 默认实现函数，所有实现结构体通用，可以覆盖
        fn f1() {
            println!("TestB::test1");
        }

        /// 抽象函数，所有实现结构体必须实现
        fn f2();

        /// 指定参数和返回值, 必须实现
        fn f3(p1: u8, p2: &u8, p3: &mut u8) -> u8;

        /// 指定实例方法,没有&self都表示是结构体函数
        fn f4(&self);
    }

    // =======trait 继承========
    trait MyTrait1: MyTrait {
        // 这个只要表示实现了MyTrait1的结构体，必须也要实现MyTrait
    }

    struct MyStruct2;

    impl MyTrait for MyStruct2 {
        /// 抽象函数，所有实现结构体必须实现
        fn f2() {}

        /// 指定参数和返回值, 必须实现
        fn f3(_: u8, _: &u8, _: &mut u8) -> u8 {
            9
        }

        /// 指定实例方法,没有&self都表示是结构体函数
        fn f4(&self) {}
    }
    impl MyTrait1 for MyStruct2 {}

    // =======trait在函数中参数的静态和动态分发========

    trait Sheep {
        fn get_name(&self) -> &str;
    }

    struct Goat {
        name: &'static str,
    }

    impl Sheep for Goat {
        fn get_name(&self) -> &str {
            self.name
        }
    }

    fn f1(t: impl Sheep) {
        println!("{}", t.get_name());
    }
    fn f2(t: Box<dyn Sheep>) {
        println!("{}", t.get_name());
    }
    fn f2_1(t: &dyn Sheep) {
        println!("{}", t.get_name());
    }
    #[test]
    fn test1() {
        let goat = Goat { name: "1" };
        f1(goat);
        let goat1 = Goat { name: "1" };
        f2_1(&goat1);
        f2(Box::new(goat1));
    }

    // =======trait在函数返回值中的静态和动态分发========
    struct Antilope {
        name: &'static str,
    }

    impl Sheep for Antilope {
        fn get_name(&self) -> &str {
            self.name
        }
    }

    fn f3(_: u8) -> impl Sheep {
        return Goat { name: "2" };
    }
    fn f4(a: u8) -> Box<dyn Sheep> {
        if a > 0 {
            return Box::new(Antilope { name: "2" });
        }
        return Box::new(Goat { name: "2" });
    }
}
